package com.fm.mediasoup.json;

import com.fm.mediasoup.sdp.Ext;
import com.fm.mediasoup.sdp.Fmtp;
import com.fm.mediasoup.sdp.RtcpFb;
import com.fm.mediasoup.sdp.Rtp;
import com.fm.mediasoup.sdp.SsrcGroup;
import com.fm.mediasoup.sdp.Ssrcs;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * 服务器 newConsume 数据返回
 */
public class RtpParameters {
    public Codec[] codecs;
    public Encoding[] encodings;
    public HeaderExtension[] headerExtensions;
    public String mid;
    public String kind;
    public Rtcp rtcp;
    public String streamId;

    public RtpParameters(Builder builder) {
        codecs = builder.codecs;
        encodings = builder.encodings;
        headerExtensions = builder.headerExtensions;
        mid = builder.mid;
        kind = builder.kind;
        rtcp = builder.rtcp;
        streamId = builder.streamId;
    }

    public RtpParameters(){

    }


    public  Rtp[] parseRtp() {
        Rtp[] rtps = new Rtp[codecs.length];
        Stream.iterate(0, i -> i + 1).limit(codecs.length).forEach(index -> {
            Codec codec = codecs[index];
            Rtp rtp = new Rtp();
            rtp.codec = codec.mimeType.replace("video/","").replace("audio/","");
            rtp.rate = codec.clockRate;
            rtp.payload = codec.payloadType;
            if (codec.channels != null) {
                rtp.encoding = codec.channels;
            }
            rtps[index] = rtp;
        });

        return rtps;
    }

    public  RtcpFb[] parseRtcpFb() {
        List<RtcpFb> rtcpFbList = new ArrayList<>();
        Stream.iterate(0, i -> i + 1).limit(codecs.length).forEach(index -> {
            Codec codec = codecs[index];
            for (RtcpFeedback rtcpFeedback : codec.rtcpFeedback) {
                RtcpFb rtcpFb = new RtcpFb();
                rtcpFb.payload = String.valueOf(codec.payloadType);
                rtcpFb.subtype = rtcpFeedback.parameter;
                rtcpFb.type = rtcpFeedback.type;
                rtcpFbList.add(rtcpFb);
            }
        });

        RtcpFb[] rtcpFbs = new RtcpFb[rtcpFbList.size()];
        rtcpFbList.toArray(rtcpFbs);
        return rtcpFbs;
    }

    public  Ext[] parseExt() {
        Ext[] exts = new Ext[headerExtensions.length];
        Stream.iterate(0, i -> i + 1).limit(headerExtensions.length).forEach(index -> {
            HeaderExtension headerExtension = headerExtensions[index];
            Ext ext = new Ext();
            ext.uri = headerExtension.uri;
            ext.value = headerExtension.id;
            exts[index] = ext;
        });

        return exts;
    }


    public  Fmtp[] parseFmtp() {
        List<Fmtp> fmtpList = new ArrayList<>();

        Stream.iterate(0, i -> i + 1).limit(codecs.length).forEach(index -> {
            Codec codec = codecs[index];
            if (codec.parameters != null && codec.parameters.apt != null) {
                Fmtp fmtp = new Fmtp();
                fmtp.payload = codec.payloadType;
                fmtp.config = "apt=" + codec.parameters.apt;
                fmtpList.add(fmtp);
            }
        });

        Fmtp[] fmtps = new Fmtp[fmtpList.size()];
        return fmtpList.toArray(fmtps);
    }

    public  SsrcGroup[] parseSSrcGroups() {
        List<SsrcGroup> ssrcGroupList = new ArrayList<>();
        Stream.iterate(0, i -> i + 1).limit(encodings.length).forEach(index -> {
            Encoding encoding = encodings[index];
            SsrcGroup ssrcGroup = new SsrcGroup();
            ssrcGroup.ssrcs = encoding.ssrc+"";
            ssrcGroup.semantics = "FID";
            if (encoding.rtx != null && encoding.rtx.ssrc != null) {
                ssrcGroup.ssrcs+=" " + encoding.rtx.ssrc;
            }
            ssrcGroupList.add(ssrcGroup);
        });
        SsrcGroup[] ssrcGroups = new SsrcGroup[ssrcGroupList.size()];
        return ssrcGroupList.toArray(ssrcGroups);
    }


    public  Ssrcs[] parseSsrcs() {
        List<Ssrcs> ssrcs = new ArrayList<>();
        Stream.iterate(0, i -> i + 1).limit(this.parseSSrcGroups().length).forEach(index -> {

            SsrcGroup ssrcGroup = this.parseSSrcGroups()[index];
            for (String ssrcString : ssrcGroup.ssrcs.split(" ")) {
                Ssrcs ssrc = new Ssrcs();
                ssrc.attribute = "cname";
                ssrc.value = rtcp.cname;
                ssrc.id = Long.parseLong(ssrcString);
                ssrcs.add(ssrc);

            }

        });
        Ssrcs[] ssrcs1 = new Ssrcs[ssrcs.size()];
        return ssrcs.toArray(ssrcs1);
    }


    @Override
    public String toString() {
        return "RtpParameters{" +
                "codecs=" + Arrays.toString(codecs) +
                ", encodings=" + Arrays.toString(encodings) +
                ", headerExtensions=" + Arrays.toString(headerExtensions) +
                ", mid='" + mid + '\'' +
                ", rtcp=" + rtcp +
                '}';
    }

    public static class Builder{

        /**
         * 设置服务端 rtcpFeed
         * @param rtcpFbs
         * @param payLoadType
         * @return
         */
        private RtcpFeedback[] rtcpFeedbacks(RtcpFb[] rtcpFbs, int payLoadType) {
            List<RtcpFeedback> rtcpFeedbackList = new ArrayList<>();
            for (RtcpFb rtcpFb : rtcpFbs) {
                if (payLoadType == Integer.parseInt(rtcpFb.payload)) {
                    rtcpFeedbackList.add(rtcpFb.conversionRtcpFeedback());
                }
            }
            RtcpFeedback[] rtcpFeedbacks = new RtcpFeedback[rtcpFeedbackList.size()];
            rtcpFeedbackList.toArray(rtcpFeedbacks);
            return rtcpFeedbacks;
        }

        public Builder setCodecs(Rtp[] rtps, RtcpFb[] rtcpFbs, String kind) {
            List<Codec> codecList = new ArrayList<>();
            for (Rtp rtp: rtps){
                Codec codec = new Codec();
                codec.clockRate = rtp.rate;
                codec.mimeType = kind+ "/" + rtp.codec;
                if(rtp.encoding != null)
                    codec.channels = rtp.encoding;
                codec.payloadType = rtp.payload;
                codec.rtcpFeedback = rtcpFeedbacks(rtcpFbs, codec.payloadType);
                codecList.add(codec);
            }
            this.codecs = new Codec[codecList.size()];
            codecList.toArray(codecs);
            return this;
        }

        public Builder setEncodings(Ssrcs[] ssrcArray) {
            List<Encoding> encodingList = new ArrayList<>();
            List<Long> ssrcList = new ArrayList<>();
            Encoding encoding = new Encoding();

            for (Ssrcs ssrcs : ssrcArray) {
                if (!ssrcList.contains(ssrcs.id) && ssrcList.size() > 0) {
                    Rtx rtx = new Rtx();
                    rtx.ssrc = ssrcs.id;

                    encoding.rtx = rtx;
                }

                if (ssrcList.size() == 0) {
                    encoding.dtx = false;
                    encoding.ssrc = ssrcs.id;
                }

                ssrcList.add(ssrcs.id);
            }
            encodingList.add(encoding);

            this.encodings = new Encoding[encodingList.size()];
            encodingList.toArray(encodings);

            return this;
        }

        /**
         * 设置扩展
         * @param exts
         * @return
         */
        public Builder setHeaderExtensions(Ext[] exts) {
            List<HeaderExtension> headerExtensionList = new ArrayList<>();
            for (Ext ext : exts) {
                HeaderExtension headerExtension = new HeaderExtension();
                headerExtension.uri = ext.uri;
                headerExtension.encrypt = false;
                headerExtension.id = ext.value;
                headerExtensionList.add(headerExtension);
            }
            this.headerExtensions = new HeaderExtension[headerExtensionList.size()];
            headerExtensionList.toArray(headerExtensions);
            return this;
        }


        public Builder setMid(String mid) {
            this.mid = mid;
            return this;
        }

        public Builder setKind(String kind) {
            this.kind = kind;
            return this;
        }

        public Builder setRtcp(Ssrcs[] ssrcArray) {
            rtcp = new Rtcp();
            for (Ssrcs ssrcs: ssrcArray) {
                if (ssrcs.attribute.equals("cname")) {
                    rtcp.cname = ssrcs.value;
                    rtcp.reducedSize = true;
                }
            }
            return this;
        }

        public Builder setStreamId(String streamId) {
            this.streamId = streamId;
            return this;
        }

        private Codec[] codecs;
        private Encoding[] encodings;
        private HeaderExtension[] headerExtensions;
        private String mid;
        private String kind;
        private Rtcp rtcp;
        private String streamId;


        public RtpParameters build(){
            return new RtpParameters(this);
        }
    }
}
